package se.sll.itintegration.catalogue.product.ejb;

import java.util.List;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import lombok.extern.slf4j.Slf4j;
import se.sll.itintegration.catalogue.product.entity.CodeEntity;
import se.sll.itintegration.catalogue.product.entity.ProductEntity;
import se.sll.service.catalogue.common.AbstractJpaFacade;

/**
 *
 * @author khaleddaham
 * @author Jiri Uosukainen
 */
@Slf4j
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class ProductEjb extends AbstractJpaFacade<ProductEntity> {

    @PersistenceContext(unitName = "productPU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    @Override
    protected void setEntityManager(EntityManager em) {
        this.em = em;
    }

    public ProductEjb() {
        super(ProductEntity.class);
    }

    public List<ProductEntity> findByName(String exactProductName) {
        log.debug("ProductEjb.findByName() was called");
        return super.findByAttributeValue("name", exactProductName);
    }

    public List<ProductEntity> findByNames(List<String> productNames) {
        log.debug("ProductEjb.findByNames() was called");
        return super.findByAttributeValues("name", productNames);
    }

    public ProductEntity findByUniqueName(String productName) {
        log.debug("ProductEjb.findByUniqueName() was called");
        List<ProductEntity> peL = super.findByAttributeValue("name", productName);

        ProductEntity pe = null;
        if (peL != null && peL.size() == 1) {
            pe = peL.get(0);
        }
        return pe;
    }

    /**
     *
     * @param productNameStart
     * @return
     */
    public List<ProductEntity> findByProductNameBeginningWith(String productNameStart) {
        TypedQuery<ProductEntity> query = getEntityManager().createNamedQuery(ProductEntity.QUERY_PRODUCTNAME_LIKE, ProductEntity.class);
        //query.setParameter("name", productNameStart+"%");
        query.setParameter("name", productNameStart + "%");

        return query.getResultList();
    }

    public List<ProductEntity> findByProductNameContains(String partOfProductName) {
        TypedQuery<ProductEntity> query = getEntityManager().createNamedQuery(ProductEntity.QUERY_PRODUCTNAME_LIKE, ProductEntity.class);
        query.setParameter("name", "%" + partOfProductName + "%");

        return query.getResultList();
    }

    /**
     * Find Products by connected codes, regardless of the code system.
     *
     * @param code The identifier of the code.
     * @return
     */
    public List<ProductEntity> findByCode(String code) {
        TypedQuery<ProductEntity> query = getEntityManager().createNamedQuery(ProductEntity.QUERY_FIND_BY_CODE, ProductEntity.class);
        query.setParameter("code", code);
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    public List<CodeEntity> getCodesByProduct(String productName) {
        return (List<CodeEntity>) em.createQuery("SELECT p.codes FROM ProductEntity p  "
                + " where p.name = ?1")
                .setParameter(1, productName).getResultList();
    }

    /**
     * Find Products by connected codes.
     *
     * @param oid The identifier of the code system.
     * @param code The identifier of the code.
     * @return
     */
    public List<ProductEntity> findByOidAndCode(String oid, String code) {
        TypedQuery<ProductEntity> query = getEntityManager().createNamedQuery(ProductEntity.QUERY_FIND_BY_OID_AND_CODE, ProductEntity.class);
        query.setParameter("oid", oid);
        query.setParameter("code", code);
        return query.getResultList();
    }

    // @TODO refactor this code
    public String generateProductId() {
        return getEntityManager().createNativeQuery(
                "SELECT MAX(CAST(name AS UNSIGNED))+1 FROM product")
                .getSingleResult().toString();
    }
}
